package services

import (
	"context"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/golang/protobuf/ptypes/wrappers"

	"kop/framework/broker"
	context2 "kop/framework/context"
	"kop/framework/errors"
	"kop/modules/battle/models/battle"
	"kop/modules/conquer/configuration/award"
	"kop/modules/conquer/configuration/buff"
	"kop/modules/item/consts"
	"kop/pb"
	"kop/pb/service"
	"kop/util/rand"

	captainC "kop/modules/captain/client"
	conquerC "kop/modules/conquer/client"
	itemC "kop/modules/item/client"
	maidC "kop/modules/maid/client"
	roleC "kop/modules/role/client"
)

type ConquerService struct {
	context2.Context
}

// 主界面
func (s *ConquerService) Main(ctx context.Context, req *empty.Empty) (*pb.Conquer, error) {

	return conquerC.ConquerService.GetConquer(ctx, req)
}

func (s *ConquerService) Start(ctx context.Context, req *wrappers.BoolValue) (*pb.RandOtherResp, error) {

	return conquerC.ConquerService.RandOther(ctx, req)
}

func (s *ConquerService) Battle(ctx context.Context, req *wrappers.Int32Value) (*pb.ConquerBattleReply, error) {

	var reply pb.ConquerBattleReply

	var roleID = s.GetRoleID(ctx)
	var conquer, err = conquerC.ConquerService.GetConquer(ctx, &empty.Empty{})
	if err != nil {
		return &reply, err
	}

	var captain = conquer.Captain.Captain

	// 有血的船长去打架 没血的还存数据里 后面随机奖励要用

	reply.Fighter1 = []*pb.Captain{captain}
	reply.Fighter2 = []*pb.Captain{captainC.GetCaptain(conquer.Role2.RoleID, req.Value)}
	reply.BattleResult, err = battle.Battle(reply.Fighter1, reply.Fighter2)
	if err != nil {
		return &reply, err
	}

	if reply.BattleResult.Win {

		var newCaptain = *captain

		for _, v := range reply.BattleResult.Battle {
			if v.P1 == newCaptain.CaptainID {
				newCaptain.Attribute.COR = v.COR1
				newCaptain.Attribute.INT = v.INT1
			}
		}

		const exp = 20

		var request = service.ConquerWinRequest{CaptainID2: req.Value, Captain: &newCaptain}
		reply.Conquer, err = conquerC.ConquerService.Win(ctx, &request)
		if err != nil {
			return &reply, err
		}

		var captain, err = captainC.AddExp(roleID, captain.CaptainID, exp)
		if err != nil {
			return &reply, err
		}

		reply.Buffs = buff.Rand3()
		reply.Points = 2
		reply.CaptainExp = &pb.CaptainExp{Exp: exp, Captain: captain}
		reply.AwardItem = &pb.AwardItem{
			RawItem: &pb.RawItem{ItemID: consts.Conquer, Number: 1},
			Item:    itemC.AddItem(roleID, consts.Conquer, 1),
		}

		// 如果团灭对手就俘虏侍女
		var allDie = false
		if reply.Conquer.Role2 == nil {
			allDie = true
		}

		if allDie {

			if conquer.Type == pb.ConquerType_ConquerRevenge {

				if res, err := maidC.MaidService.SaveFromEnemy(ctx, &wrappers.Int32Value{Value: conquer.Role2.RoleID}); err == nil {
					reply.MaidID = res.Value
				}

			} else {

				if res, err := maidC.MaidService.Capture(ctx, &service.CaptureRequest{MasterID: conquer.Role2.RoleID, Name: conquer.Role2.Name}); err == nil {
					reply.MaidID = res.Value

					// 侍女被俘虏：[B玩家] 俘虏了 [A玩家] 的侍女 [侍女名称]
					_ = broker.ServerPublish(s.GetServerID(ctx), pb.WsCode_CodeMessage, &pb.ServerMessage{Type: 7, Name: []string{roleC.GetRole(roleID).Name, conquer.Role2.Name}, Nums: []int32{reply.MaidID}})
				}
			}
		}

	} else {
		reply.Conquer, err = conquerC.ConquerService.Loss(context.Background(), &service.RoleRequest{RoleID: roleID})
	}

	if reply.Conquer != nil {
		// 保留战斗类型
		reply.Conquer.Type = conquer.Type
	}

	if reply.Conquer.Role2 != nil {
		Captains(reply.Conquer.Role2.Captains2).setSkillNil()
	}

	return &reply, err
}

func (s *ConquerService) Buff(ctx context.Context, req *wrappers.Int32Value) (*pb.ConquerAttackReply, error) {

	var reply pb.ConquerAttackReply

	var conf, err = buff.GetByBuffID(req.Value)
	if err != nil {
		return &reply, err
	}

	var roleID = s.GetRoleID(ctx)
	if reply.Item, err = itemC.DelItem(roleID, s.GetServerID(ctx), conf.ItemID, conf.Price); err != nil {
		return &reply, err
	}

	reply.Conquer, err = conquerC.ConquerService.Buff(context.Background(), &service.DefaultRequest{RoleID: roleID, Value: req.Value})
	if err != nil {
		return &reply, err
	}

	Captains(reply.Conquer.Role2.Captains2).setSkillNil()

	return &reply, err
}

func (s *ConquerService) ChooseAward(ctx context.Context, req *wrappers.Int32Value) (*pb.ConquerAwardReply, error) {

	var reply pb.ConquerAwardReply

	var roleID = s.GetRoleID(ctx)
	var conquer, err = conquerC.ConquerService.GetConquer(ctx, &empty.Empty{})
	if err != nil {
		return &reply, err
	}

	if conquer.Captain.WinNum%3 != 0 {
		return &reply, errors.ParamError
	}

	var values []rand.Value
	for _, conf := range award.Configs {
		values = append(values, conf)
	}

	// 从配置里随机3个奖励
	var res = rand.WithWeight(values, 3)

	reply.Option = make([]*pb.ConquerAwardOption, 3)
	for k, v := range res {
		var conf = v.(award.Conf)

		var num = rand.Int32(conf.CountMin, conf.CountMax)

		switch conf.AwardType {
		case 1:
			// 船长经验

			var captain = conquer.Captain.Captain

			if int(req.Value-1) == k {
				captain, err = captainC.AddExp(roleID, captain.CaptainID, num)
				if err != nil {
					return &reply, err
				}
			}

			reply.Option[k] = &pb.ConquerAwardOption{
				Option: &pb.ConquerAwardOption_CaptainExp{CaptainExp: &pb.CaptainExp{Exp: num, Captain: captain}},
			}

		case 2:
			// 船长碎片

			var itemID = 103000 + conquer.Captain.Captain.CaptainID

			var awardItem = &pb.AwardItem{RawItem: &pb.RawItem{ItemID: itemID, Number: num}}
			if int(req.Value-1) == k {
				awardItem.Item = itemC.AddItem(roleID, itemID, num)
			}

			reply.Option[k] = &pb.ConquerAwardOption{
				Option: &pb.ConquerAwardOption_AwardItem{AwardItem: awardItem},
			}

		case 3:
			// 道具
			var awardItem = &pb.AwardItem{RawItem: &pb.RawItem{ItemID: conf.Value, Number: num}}
			if int(req.Value-1) == k {
				awardItem.Item = itemC.AddItem(roleID, conf.Value, num)
			}

			reply.Option[k] = &pb.ConquerAwardOption{
				Option: &pb.ConquerAwardOption_AwardItem{AwardItem: awardItem},
			}
		}
	}

	return &reply, nil
}

const (
	AttackItem = 101053 // 追击令
	Compass    = 101054 // 追踪罗盘
)

// 追击
func (s *ConquerService) Attack(ctx context.Context, req *pb.ConquerAttackRequest) (*pb.ConquerAttackReply, error) {

	var reply pb.ConquerAttackReply
	var roleID = s.GetRoleID(ctx)

	var itemID int32 = AttackItem
	if req.Type == pb.ConquerType_ConquerSearch {
		itemID = Compass
	}

	var err error
	if reply.Item, err = itemC.DelItem(roleID, s.GetServerID(ctx), itemID, 1); err != nil {
		return &reply, err
	}

	captain := captainC.GetCaptain(roleID, req.CaptainID)

	reply.Conquer, err = conquerC.ConquerService.Attack(context.Background(),
		&service.ConquerAttackRequest{RoleID: roleID, RoleID2: req.RoleID2, Captain: captain, Type: req.Type})
	if err != nil {
		return &reply, err
	}

	reply.Conquer.Role2.Name = roleC.GetRole(req.RoleID2).Name
	Captains(reply.Conquer.Role2.Captains2).setSkillNil()

	return &reply, err
}

func (s *ConquerService) ServerReports(ctx context.Context, req *empty.Empty) (*pb.ConquerReports, error) {

	return conquerC.ConquerService.ServerReports(context.Background(), &wrappers.Int32Value{Value: s.GetServerID(ctx)})
}

func (s *ConquerService) MyReports(ctx context.Context, req *empty.Empty) (*pb.MyReportsResp, error) {

	return conquerC.ConquerService.MyReports(context.Background(), &service.RoleRequest{RoleID: s.GetRoleID(ctx)})
}

func (s *ConquerService) Search(ctx context.Context, req *wrappers.Int32Value) (*pb.ConquerSearchReply, error) {

	var res, err = conquerC.ConquerService.Search(context.Background(), req)
	if err != nil {
		return &pb.ConquerSearchReply{}, err
	}

	var role *pb.Role
	if res.Ok {
		role = roleC.GetRole(req.Value)
	}

	return &pb.ConquerSearchReply{
		Ok:     res.Ok,
		Points: res.Points,
		Role:   role,
	}, nil
}
